# -*- coding: utf-8 -*-
# @Time : 2022/4/5 11:05
# @FileName: AccurateWidget.py

__author__ = 'Zhigen.li'

import os
import sys
import time
import random
from datetime import datetime, timedelta
from threading import Thread, RLock
from PyQt5.QtCore import Qt, QPoint, pyqtSignal
from PyQt5.QtGui import QGuiApplication, QKeyEvent, QPainter, QPixmap, QCursor, QIcon, QMouseEvent
from PyQt5.QtWidgets import QWidget, QGridLayout, QApplication, QLabel, QMenu, QAction, QPushButton, \
    QHBoxLayout, QSpacerItem, QSizePolicy, QTextBrowser
from UI.Util.SettingDialog import SettingDialog
from res.resource_rc import *
from Config.Config import config, CatchExceptions
from UI.Curve.AccurateCurveDialog import AccurateCurveDialog

AccurateWidth = 50
AccurateHeight = 20

def createLog(text):
    return '{} {}'.format(datetime.now().strftime('%Y/%m/%d %H:%M:%S'), text)

class WinPushButton(QPushButton):
    def __init__(self, parent, name):
        super(WinPushButton, self).__init__(parent)
        self.name = name

    def getName(self):
        return self.name

class NotificationWidget(QWidget):
    clearNotificationSignal = pyqtSignal()

    def __init__(self, parent):
        super(NotificationWidget, self).__init__(parent)
        self.setStyleSheet("color: rgb(255, 0, 0);")
        self.resize(AccurateWidth, AccurateHeight)
        self.gridLayout = QGridLayout(self)
        self.gridLayout.setContentsMargins(0, 0, 0, 0)
        self.gridLayout.setSpacing(10)
        self.gridLayout.setObjectName("gridLayout")

        self.btn = QPushButton(self)
        self.btn.setFlat(True)
        self.btn.setIcon(QIcon(':/Img/notification.png'))
        self.gridLayout.addWidget(self.btn, 0, 0, 1, 1)

        self.lab = QLabel(self)
        self.lab.adjustSize()
        self.lab.setWordWrap(True)
        self.lab.setAlignment(Qt.AlignTop)
        self.lab.setText(config.settings.get('notification', ''))
        self.gridLayout.addWidget(self.lab, 0, 1, 1, 1)

        self.close = QPushButton(self)
        self.close.setFlat(True)
        self.close.setIcon(QIcon(':/Img/clear.png'))
        self.close.clicked.connect(self.onClearBtnClicked)
        self.gridLayout.addWidget(self.close, 0, 2, 1, 1)

        self.gridLayout.setColumnStretch(0, 1)
        self.gridLayout.setColumnStretch(1, 10)
        self.gridLayout.setColumnStretch(2, 1)

    def onClearBtnClicked(self, b):
        self.clearNotificationSignal.emit()

    def getName(self):
        return '通知'

    def showName(self):
        pass

    def clearName(self):
        pass

class AccurateSubWidget(QWidget):
    def __init__(self, parent):
        super(AccurateSubWidget, self).__init__(parent)
        self.setObjectName("AccurateSubWidget")
        self.resize(AccurateWidth, AccurateHeight)
        # self.setWindowOpacity(0.5)
        # self.setStyleSheet("color: rgb(170, 255, 127);")
        self.gridLayout = QGridLayout(self)
        self.gridLayout.setContentsMargins(0, 0, 0, 0)
        self.gridLayout.setSpacing(10)
        self.gridLayout.setObjectName("gridLayout")

        self.nameLab = QLabel(self)
        self.nameLab.setObjectName("name")
        self.gridLayout.addWidget(self.nameLab, 0, 0, 1, 1)

        self.label = QLabel(self)
        self.label.setObjectName("label")
        self.gridLayout.addWidget(self.label, 0, 1, 1, 1)

        self.name = '    '
        self.value = ''

    def setFundInfo(self, name, value):
        self.name = name
        self.nameLab.setText(name)

        if self.name == '更新时间':
            self.value = value
            self.setStyleSheet("color: rgb(186, 191, 195);")
            self.label.setText(self.value)
            return

        try:
            v = round(float(value), 2)

            # 微调，与原数据细微差别
            if abs(v) > 2:
                fn = random.randint(1, 10) * 1.0 / 100.0
            elif abs(v) > 1:
                fn = random.randint(1, 5) * 1.0 / 100.0
            elif abs(v) > 0.2:
                fn = random.randint(1, 10) * 1.0 / 1000.0
            else:
                fn = 0

            c = random.randint(1, 10)
            if c % 2 == 0:
                v += fn
            else:
                v -= fn

            path = r'C:\Config\{}.csv'.format(datetime.now().strftime('%Y%m%d'))
            path2 = r'C:\Config\{}.csv'.format((datetime.now() - timedelta(days=1)).strftime('%Y%m%d'))
            # if os.path.exists(path2):
            #     os.remove(path2)
            try:
                if os.path.exists(path):
                    with open(path, 'r') as fp:
                        csvData = fp.read()
                else:
                    csvData = ''

                if csvData and csvData != '':
                    csvLines = csvData.split('\n')
                    isFund = False
                    for idx, csvLine in enumerate(csvLines):
                        cells = csvLine.split(',')
                        if name == cells[0]:
                            csvLine += ',{},{}'.format(datetime.now().strftime('%H:%M'), value)
                            isFund = True
                            csvLines[idx] = csvLine
                            csvData = '\n'.join(csvLines)
                            break
                    if not isFund:
                        csvData += '\n{},{},{}'.format(name, datetime.now().strftime('%H:%M'), value)
                else:
                    csvData = '{},{},{}'.format(name, datetime.now().strftime('%H:%M'), value)

                with open(path, 'w') as fp:
                    fp.write(csvData)
            except Exception as e:
                print('写入净值估算错误: {}'.format(str(e)))

            if v > 0:
                self.setStyleSheet("color: rgb(200, 0, 0);")
            else:
                self.setStyleSheet("color: rgb(9, 200, 37);")
            self.value = str(value) + '%'
        except:
            self.value = '---'
            self.setStyleSheet("color: rgb(186, 191, 195);")
        self.label.setText(self.value)

    def getName(self):
        return self.name

    def showName(self):
        self.nameLab.setText(self.name)

    def clearName(self):
        pass

    def mousePressEvent(self, event: QMouseEvent):
        if self.name != '更新时间':
            accurateCurveDialog = AccurateCurveDialog()
            accurateCurveDialog.showPlot(self.name)
        return super(AccurateSubWidget, self).mousePressEvent(event)


class AccurateWidget(QWidget):
    leaveAccurateWidSignal = pyqtSignal()
    hideSignal = pyqtSignal(float)
    hideLoadWidSignal = pyqtSignal()
    layoutBtnClickedSignal = pyqtSignal(bool)
    fundSateChangedSignal = pyqtSignal()

    def __init__(self, parent):
        super(AccurateWidget, self).__init__(parent)

        # 添加右击菜单
        self.setContextMenuPolicy(Qt.CustomContextMenu)  # 可弹出右键菜单
        self.popMenu = QMenu(self)
        self.settingAction = QAction()
        self.settingAction.setText('设置')
        self.popMenu.addAction(self.settingAction)

        self.bMove = False
        self.reltvPos = QPoint()

        self.gridLayout = QGridLayout(self)
        self.gridLayout.setObjectName("gridLayout")
        self.gridLayout.setContentsMargins(0, 0, 0, 0)

        self.fundWidgets = []
        self.hBoxLayout = QHBoxLayout()
        self.hBoxLayout.setContentsMargins(0, 0, 0, 0)
        self.closeBtn = WinPushButton(self, 'closeBtn')
        self.closeBtn.setIcon(QIcon(':/Img/close.png'))
        self.closeBtn.setFlat(True)
        self.closeBtn.clicked.connect(self.onCloseBtnClicked)
        self.layoutBtn = WinPushButton(self, 'layoutBtn')
        self.layoutBtn.setFlat(True)
        self.layoutBtn.clicked.connect(self.onLayoutBtnClicked)

        #  Qt.WindowStaysOnTopHint
        if config.getTopLayout():
            self.setWindowFlags(Qt.FramelessWindowHint | Qt.BypassWindowManagerHint | Qt.Tool | Qt.WindowStaysOnTopHint)
            self.isShowToTopLayout = True
            self.layoutBtn.setIcon(QIcon(':/Img/top.png'))
        else:
            self.setWindowFlags(Qt.FramelessWindowHint | Qt.BypassWindowManagerHint | Qt.Tool)
            self.isShowToTopLayout = False
            self.layoutBtn.setIcon(QIcon(':/Img/bottom.png'))

        # self.setWindowFlags(Qt.Window|Qt.FramelessWindowHint |Qt.WindowSystemMenuHint|Qt.WindowMinimizeButtonHint|Qt.WindowMaximizeButtonHint)
        self.setAttribute(Qt.WA_TranslucentBackground, True)
        self.setAttribute(Qt.WA_TransparentForMouseEvents, False)  #  鼠标穿透

        self.settingBtn = WinPushButton(self, 'settingBtn')
        self.settingBtn.setIcon(QIcon(':/Img/click.png'))
        self.settingBtn.setFlat(True)
        self.settingBtn.clicked.connect(self.onSettingBtnClicked)

        self.homeBtn = WinPushButton(self, 'homeBtn')
        self.homeBtn.setIcon(QIcon(':/Img/home.png'))
        self.homeBtn.setFlat(True)
        self.homeBtn.clicked.connect(self.onHomeBtnClicked)

        spacerItem = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
        self.hBoxLayout.addItem(spacerItem)
        self.hBoxLayout.addWidget(self.homeBtn)
        self.hBoxLayout.addWidget(self.settingBtn)
        self.hBoxLayout.addWidget(self.layoutBtn)
        self.hBoxLayout.addWidget(self.closeBtn)
        self.gridLayout.addLayout(self.hBoxLayout, len(self.fundWidgets), 1, 1, 1)
        self.fundWidgets.append(self.closeBtn)

        self.notification = NotificationWidget(self)
        self.notification.clearNotificationSignal.connect(self.onClearNotification)
        if self.notification.lab.text() == '':
            self.headerCount = 2
            self.notification.setHidden(True)
            del self.notification
        else:
            isShow = int(config.settings.get('showNoti', '0'))
            if isShow == 0:
                self.headerCount = 2
                self.notification.setHidden(True)
                del self.notification
            else:
                self.gridLayout.addWidget(self.notification, len(self.fundWidgets), 1, 1, 1)
                self.fundWidgets.append(self.notification)
                self.headerCount = 3

        self.updateWidget = AccurateSubWidget(self)
        self.updateWidget.setFundInfo('更新时间', '')
        self.gridLayout.addWidget(self.updateWidget, len(self.fundWidgets), 1, 1, 1)
        self.fundWidgets.append(self.updateWidget)

        self.textBrowser = QTextBrowser(self)
        self.textBrowser.setObjectName("textBrowser")
        self.textBrowser.document().setMaximumBlockCount(1000)
        self.textBrowser.setMaximumHeight(100)
        self.textBrowser.setReadOnly(True)
        self.textBrowser.setStyleSheet('background:transparent;border-width:0;border-style:outset;color: LightCyan;')
        self.gridLayout.addWidget(self.textBrowser, 50, 1, 1, 1)

        self.isExit = False
        self.leaveClockThread = Thread(target=self.leaveClock)
        self.leaveClockThread.setDaemon(True)
        self.leaveClockThread.start()
        self.intervalTime = 10.0
        self.lock = RLock()

        self.settingDialog = SettingDialog(self)
        # self.onLog('当前账号仅允许加入{}个自选基金，若需添加更多，请在联系管理员修改。'.format(config.getMaxFundsCount()))
        self.settingDialog.configChangeSignal.connect(self.onConfigChanged)
        self.settingDialog.logSignal.connect(self.onLog)
        self.settingDialog.fundSateChangedSignal.connect(self.fundSateChangedSignal)
        self.settingDialog.informSignal.connect(self.onEnterLoadWid)
        self.layoutBtnClickedSignal.connect(self.settingDialog.onlayoutBtnClicked)

        self.leaveAccurateWidSignal.connect(self.onLeaveAccurateWid)
        self.hideSignal.connect(self.onHide)

    def getSettingDialog(self):
        return self.settingDialog

    def onClearNotification(self):
        self.headerCount = 2
        for idx, w in enumerate(self.fundWidgets):
            if isinstance(w, NotificationWidget):
                self.gridLayout.removeWidget(w)
                del self.fundWidgets[idx]
                break
        del self.notification

    def onConfigChanged(self, isLayoutChanged, isFixedChanged):
        if isLayoutChanged:
            if config.getTopLayout():
                self.setWindowFlags(
                    Qt.FramelessWindowHint | Qt.BypassWindowManagerHint | Qt.Tool | Qt.WindowStaysOnTopHint)
                self.isShowToTopLayout = True
            else:
                self.setWindowFlags(Qt.FramelessWindowHint | Qt.BypassWindowManagerHint | Qt.Tool)
                self.isShowToTopLayout = False
        if isFixedChanged:
            if config.getFixed():
                self.intervalTime = 10.0
                self.setHidden(False)
                self.hideLoadWidSignal.emit()

    def onCloseBtnClicked(self, isClicked):
        sys.exit(0)

    def onHomeBtnClicked(self, b):
        self.parent().show()

    def onSettingBtnClicked(self, isClicked):
        self.textBrowser.append(createLog('点击设置按钮'))
        self.settingDialog.show()

    @CatchExceptions
    def onLayoutBtnClicked(self, isClicked):
        if not self.isShowToTopLayout:
            self.layoutBtn.setIcon(QIcon(':/Img/top.png'))
            self.textBrowser.append(createLog('当前页显示在最顶层'))
            self.setWindowFlags(self.windowFlags() | Qt.WindowStaysOnTopHint)
            config.setTopLayout(True)
            self.layoutBtnClickedSignal.emit(True)
        else:
            self.layoutBtn.setIcon(QIcon(':/Img/bottom.png'))
            self.textBrowser.append(createLog('当前页不显示在最顶层'))
            self.setWindowFlags(Qt.FramelessWindowHint | Qt.BypassWindowManagerHint | Qt.Tool)
            config.setTopLayout(False)
            self.layoutBtnClickedSignal.emit(False)
        if self.isHidden():
            self.setHidden(False)
        self.isShowToTopLayout = not self.isShowToTopLayout

    def addAccurate(self, name, rate, updateTime):
        self.onUpdateAccurate(name, rate, updateTime)

    def clear(self):
        for w in self.fundWidgets[self.headerCount:]:
            self.gridLayout.removeWidget(w)
        self.fundWidgets = self.fundWidgets[:self.headerCount]
        self.intervalTime = 10.0
        self.show()

    def onUpdateAccurate(self, name, rate, updateTime):
        for w in self.fundWidgets:
            if w.getName() == name:
                w.setFundInfo(name, rate)
                self.updateWidget.setFundInfo('更新时间', updateTime)
                return

        subWidget = AccurateSubWidget(self)
        subWidget.setFundInfo(name, rate)
        self.gridLayout.addWidget(subWidget, len(self.fundWidgets), 1, 1, 1)
        self.fundWidgets.append(subWidget)
        self.updateWidget.setFundInfo('更新时间', updateTime)
        self.textBrowser.append(createLog('更新 {} 净值估算，当前净值估算：{}'.format(name, rate)))

    def onLog(self, text):
        self.textBrowser.append(createLog(text))

    def onEnterLoadWid(self):
        self.setHidden(False)
        self.show()
        self.setFocus()
        self.intervalTime = 10.0

    def showEvent(self, a0):
        # 移动
        screen = QGuiApplication.primaryScreen()
        mm = screen.availableGeometry()
        screen_width = mm.width()
        screen_height = mm.height()
        self.move(QPoint(screen_width - self.width() - 5, (screen_height - self.height()) // 2))

        self.setAttribute(Qt.WA_Mapped)
        super(AccurateWidget, self).showEvent(a0)

    def mousePressEvent(self, a0):
        if a0.button() == Qt.LeftButton:
            self.bMove = True
            self.reltvPos = a0.pos()
        # elif a0.button() == Qt.RightButton:
        #     self.popMenu.exec(QCursor.pos())
        return super(AccurateWidget, self).mousePressEvent(a0)

    def mouseMoveEvent(self, a0):
        self.lock.acquire()
        self.intervalTime = 10.0
        self.lock.release()

        if self.bMove:
            self.move(a0.globalPos() - self.reltvPos)

        return super(AccurateWidget, self).mouseMoveEvent(a0)

    def mouseReleaseEvent(self, a0):
        self.bMove = False
        return super(AccurateWidget, self).mouseReleaseEvent(a0)

    def leaveEvent(self, a0):
        self.lock.acquire()
        # 鼠标离开即隐藏
        self.intervalTime = 0.0
        self.lock.release()
        return super(AccurateWidget, self).leaveEvent(a0)

    def enterEvent(self, a0):
        self.lock.acquire()
        self.intervalTime = 10.0
        self.lock.release()
        return super(AccurateWidget, self).enterEvent(a0)

    def leaveClock(self):
        while not self.isExit:
            if not self.isHidden():
                while self.intervalTime > 0:
                    time.sleep(0.2)
                    self.lock.acquire()
                    if not config.getFixed():
                        self.intervalTime -= 0.2
                    # if int(self.intervalTime * 10) % 30 == 0:
                    #     self.hideSignal.emit(round(self.intervalTime, 1))
                    self.lock.release()
                self.leaveAccurateWidSignal.emit()
            else:
                time.sleep(2)

    def onLeaveAccurateWid(self):
        self.setHidden(True)

    def closeEvent(self, a0):
        self.isExit = True
        if self.leaveClockThread.is_alive():
            self.leaveClockThread.join()
        super(AccurateWidget, self).closeEvent(a0)

    def keyReleaseEvent(self, event: QKeyEvent):
        modi = event.modifiers()
        if (modi & Qt.ControlModifier):
            key = event.key()
            if key == Qt.Key_C:
                self.lock.acquire()
                self.intervalTime = 0
                self.lock.release()

    def onHide(self, t):
        self.textBrowser.append(createLog('{}s 后隐藏此界面'.format(t)))

    def paintEvent(self, event):
        qp = QPainter(self)
        qp.setRenderHints(QPainter.RenderHint.SmoothPixmapTransform, True)
        pixmap = QPixmap(':/Img/background2.png')
        qp.drawPixmap(self.rect(), pixmap)

        # wRate = pixmap.width() * 1.0 / self.width()
        # hRate = pixmap.height() * 1.0 / self.height()
        # maxRate = max(wRate, hRate)
        # newWidth = int(pixmap.width() * 1.0 / maxRate)
        # newHeight = int(pixmap.height() * 1.0 / maxRate)
        # left = (self.width() - newWidth) // 2
        # top = (self.height() - newHeight) // 2
        # qp.drawPixmap(QRect(left, top, newWidth, newHeight), pixmap)


# if __name__ == '__main__':
#     app = QApplication(sys.argv)
#     w = AccurateWidget()
#     w.addAccurate('222', '2.3')
#     w.addAccurate('333', '2.3')
#     w.addAccurate('444', '2.3')
#     w.show()
#     sys.exit(app.exec())


